package com.qys.livesMall.app.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.qys.livesMall.app.user.event.LimitEvent;
import com.qys.livesMall.app.user.model.dto.sys.SysLimitUrlPageDTO;
import com.qys.livesMall.app.user.model.entity.Limit;
import com.qys.livesMall.app.user.mapper.LimitMapper;
import com.qys.livesMall.app.user.model.entity.LimitUrl;
import com.qys.livesMall.app.user.model.pojo.LimitCachePOJO;
import com.qys.livesMall.app.user.model.pojo.UserLimitEventPOJO;
import com.qys.livesMall.app.user.model.vo.sys.LimitVO;
import com.qys.livesMall.app.user.service.LimitService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qys.livesMall.app.user.service.LimitUrlService;
import com.qys.livesMall.cache.RedisCache;
import com.qys.livesMall.common.exception.QysException;
import com.qys.livesMall.common.result.R;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.qys.livesMall.app.user.constants.RedisConstant.LIMIT_URLS;
import static com.qys.livesMall.app.user.constants.RedisConstant.LIMIT_USER;

/**
 * <p>
 * 用户权限控制 服务实现类
 * </p>
 *
 * @author
 * @since 2023-07-31
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class LimitServiceImpl extends ServiceImpl<LimitMapper, Limit> implements LimitService {

    private final LimitUrlService limitUrlService;
    private final ApplicationContext applicationContext;
    private final RedisCache redisCache;

    @Override
    public Limit getByUserIdAndLimitUrlId(Long userId, Long limitUrlId) {
        Limit limit = getOne(Wrappers.<Limit>lambdaQuery()
                .eq(Limit::getUserId, userId)
                .eq(Limit::getLimitUrlId, limitUrlId)
        );
        if (limit == null) {
            List<Limit> init = processLimit(userId);
            for (Limit l : init) {
                if (l.getLimitUrlId().equals(limitUrlId)) {
                    limit = l;
                }
            }
        }
        return limit;
    }

    /**
     * 初始化用户权限
     */
    @Override
    public List<Limit> processLimit(Long userId) {
        List<Limit> limitList = baseMapper.selectList(Wrappers.<Limit>lambdaQuery().eq(Limit::getUserId, userId));
        List<LimitUrl> urlList = limitUrlService.list();
        if (limitList.size() < urlList.size()) {
            List<Limit> addList = new ArrayList<>();
            for (LimitUrl url : urlList) {
                long count = count(Wrappers.<Limit>lambdaQuery()
                        .eq(Limit::getUserId, userId)
                        .eq(Limit::getLimitUrlId, url.getId())
                );
                if (count == 0) {
                    Limit limit = new Limit();
                    limit.setUserId(userId);
                    limit.setStatus((byte) 1);
                    limit.setLimitUrlId(url.getId());
                    limitList.add(limit);
                    addList.add(limit);
                }
            }
            if (addList.size() > 0) {
                saveBatch(addList);
            }
            return limitList;
        }
        return limitList;
    }

    @Override
    public List<LimitVO> userLimit(SysLimitUrlPageDTO queryDTO) {
        List<LimitUrl> list = limitUrlService.list(Wrappers.<LimitUrl>lambdaQuery()
                .eq(LimitUrl::getStatus, 0)
                .eq(LimitUrl::getType, queryDTO.getType()));
        List<LimitVO> limitVOList = BeanUtil.copyToList(list, LimitVO.class);
        List<Limit> limitList = processLimit(queryDTO.getUserId());
        Map<Long, Limit> limitMap = limitList.stream().collect(Collectors.toMap(Limit::getLimitUrlId, Function.identity()));
        limitVOList.forEach(e -> {
            Limit limit = limitMap.get(e.getId());
            e.setLimitUrlId(e.getId());
            e.setId(limit.getId());
            e.setStatus(limit.getStatus());
        });
        return limitVOList;
    }


    @Override
    @PostConstruct
    public void init() {
        List<Limit> list = list();
        if (list == null || list.size() == 0) {
            redisCache.deleteObject(LIMIT_URLS);
            return;
        }
        redisCache.deleteAll(LIMIT_USER);
        Map<Long, List<Limit>> userIdMapLimit = list.stream().collect(Collectors.groupingBy(Limit::getUserId));
        userIdMapLimit.forEach((k, v) -> {
            List<LimitCachePOJO> cache = BeanUtil.copyToList(v, LimitCachePOJO.class);
            redisCache.setCacheObject(LIMIT_USER + k,cache);
        });
    }


    @Override
    public void coLimit(String id) {
        Limit limit = baseMapper.selectById(id);
        UserLimitEventPOJO pojo = new UserLimitEventPOJO();
        pojo.setUserIds(List.of(limit.getUserId()));
        pojo.setLimitUrlId(limit.getLimitUrlId());
        pojo.setStatus((byte) (limit.getStatus() == 1 ? 2 : 1));
        applicationContext.publishEvent(new LimitEvent(pojo));
    }

    /**
     * 批量 关闭/打开权限
     */
    @Override
    public void coLimitBatch(List<Long> userIdList, Long limitUrlId, Byte status) {
        UserLimitEventPOJO pojo = new UserLimitEventPOJO();
        pojo.setUserIds(userIdList);
        pojo.setLimitUrlId(limitUrlId);
        pojo.setStatus(status);
        applicationContext.publishEvent(new LimitEvent(pojo));
    }


}
